package com.fengmi.service.impl;

import com.fengmi.api.goods.GoodsApi;
import com.fengmi.entity.dto.SearchDTO;
import com.fengmi.entity.goods.ESGoods;
import com.fengmi.entity.goods.MallGoods;
import com.fengmi.entity.goods.PageSearchResult;
import com.fengmi.entity.vo.PageResultVO;
import com.fengmi.entity.vo.ResultVO;
import com.fengmi.service.ISearchService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SearchService implements ISearchService {
    @Autowired
    private ElasticsearchRestTemplate template;
    @Autowired
    private GoodsApi goodsApi;
    @Override
    public ResultVO goods2es() {

        //删除索引库
        template.deleteIndex(ESGoods.class);

        //创建索引库
        template.createIndex(ESGoods.class);
        template.putMapping(ESGoods.class);


        List<MallGoods> goods = goodsApi.findGoods();

        if(goods==null)
            return new ResultVO(false,"同步数据失败");

        //todo 666
        List<Object> list = goods.stream().map(spu -> {
            ESGoods esGoods = new ESGoods();
            esGoods.setSpuId(spu.getSpuId());

            esGoods.setBrandId(spu.getBrand().getId());
            esGoods.setBrandName(spu.getBrand().getName());


            esGoods.setCid1id(spu.getCat1().getId());
            esGoods.setCat1name(spu.getCat1().getName());
            esGoods.setCid2id(spu.getCat2().getId());
            esGoods.setCat2name(spu.getCat2().getName());
            esGoods.setCid3id(spu.getCat3().getId());
            esGoods.setCat3name(spu.getCat3().getName());

            esGoods.setCreateTime(new Date());
            esGoods.setGoodsName(spu.getGoodsName());
            esGoods.setPrice(spu.getPrice().doubleValue());

            if(spu.getAlbumPics() != null){
                String[] imgArr = spu.getAlbumPics().split(",");
                if(imgArr!=null && imgArr.length>0)
                    esGoods.setImageUrl(imgArr[0]);
            }


            return esGoods;
        }).collect(Collectors.toList());

        template.save(list);

        return new ResultVO(true,"数据同步成功");
    }

    @Override
    public PageResultVO<ESGoods> search(SearchDTO searchDTO) {

        if(searchDTO==null)
            return new PageResultVO<>(false,"参数不合法");
        //1.关键字查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(!StringUtils.isEmpty(searchDTO.getKeyword())){
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            MatchQueryBuilder brandName = QueryBuilders.matchQuery("brandName", searchDTO.getKeyword());
            MatchQueryBuilder cat3name = QueryBuilders.matchQuery("cat3name", searchDTO.getKeyword());
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);
        }
        //2.分页查询
        PageRequest pageRequest = PageRequest.of((searchDTO.getPage()-1)>=0?searchDTO.getPage()-1:0,searchDTO.getSize());
        //3.按照商品的品牌和商品的分类进行聚合
        TermsAggregationBuilder brandNameTermsAggregationBuilder = AggregationBuilders.terms("brand_agg").field("brandName").size(10);
        TermsAggregationBuilder cat3nameTermsAggregationBuilder = AggregationBuilders.terms("cat3name_agg").field("cat3name").size(30);

        //4.根据商品品牌和第三级分类进行过滤
        if(!StringUtils.isEmpty(searchDTO.getBrandNameFilter())){
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", searchDTO.getBrandNameFilter());
            boolQueryBuilder.filter(brandName);
        }
        if(!StringUtils.isEmpty(searchDTO.getCat3NameFilter())){
            TermQueryBuilder cat3name = QueryBuilders.termQuery("cat3name", searchDTO.getCat3NameFilter());
            boolQueryBuilder.filter(cat3name);
        }

        //5.根据价格排序
        FieldSortBuilder price = null;
        if(!StringUtils.isEmpty(searchDTO.getSort())&&"desc".equals(searchDTO.getSort())){
            price = SortBuilders.fieldSort("price").order(SortOrder.DESC);
        }
        if(!StringUtils.isEmpty(searchDTO.getSort())&&"asc".equals(searchDTO.getSort())){
            price = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        }

        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder()
                //指定查询方式
                .withQuery(boolQueryBuilder)
                //执行分页
                .withPageable(pageRequest)
                //指定高亮
                .withHighlightBuilder(getHighlightBuilder("goodsName"))
                //进行聚合
                .addAggregation(brandNameTermsAggregationBuilder)
                .addAggregation(cat3nameTermsAggregationBuilder);
                //执行排序
                if(price!=null){
                    builder.withSort(price);
                }


        SearchHits<ESGoods> search = template.search(builder.build(), ESGoods.class);

        PageSearchResult pageResultVO = new PageSearchResult();
        //获取总记录数
        long totalHits = search.getTotalHits();
        pageResultVO.setTotal(totalHits);

        //获取文档列表
        List<ESGoods> goodsList = search.getSearchHits().stream().map(hit -> {
            ESGoods esGoods = hit.getContent();
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            highlightFields.forEach((k,v)->{
                String s =(v!=null)&&v.size()>0? v.get(0):"";
                if("goodsName".equals(k)){
                    esGoods.setGoodsName(s);
                }
            });
            return esGoods;
        }).collect(Collectors.toList());


        //获取聚合信息
        Aggregations aggregations = search.getAggregations();
        Terms brand_agg = aggregations.get("brand_agg");
        List<? extends Terms.Bucket> brandAggBuckets = brand_agg.getBuckets();
        List<String> brandNameList = brandAggBuckets.stream().map(item -> (String)item.getKey()).collect(Collectors.toList());

        Terms cat3name_agg = aggregations.get("cat3name_agg");
        List<String> cat3nameList = cat3name_agg.getBuckets().stream().map(item -> (String)item.getKey()).collect(Collectors.toList());

        pageResultVO.setBrandNameList(brandNameList);
        pageResultVO.setCat3nameList(cat3nameList);

        pageResultVO.setData(goodsList);

        return pageResultVO;
    }

    @Override
    public ResultVO goodsToBu(MallGoods spu) {
        if(spu ==null)
            return new ResultVO(false,"同步失败");

        ESGoods esGoods = new ESGoods();
        esGoods.setSpuId(spu.getSpuId());

        esGoods.setBrandId(spu.getBrand().getId());
        esGoods.setBrandName(spu.getBrand().getName());


        esGoods.setCid1id(spu.getCat1().getId());
        esGoods.setCat1name(spu.getCat1().getName());
        esGoods.setCid2id(spu.getCat2().getId());
        esGoods.setCat2name(spu.getCat2().getName());
        esGoods.setCid3id(spu.getCat3().getId());
        esGoods.setCat3name(spu.getCat3().getName());

        esGoods.setCreateTime(new Date());
        esGoods.setGoodsName(spu.getGoodsName());
        esGoods.setPrice(spu.getPrice().doubleValue());

        if(spu.getAlbumPics() != null){
            String[] imgArr = spu.getAlbumPics().split(",");
            if(imgArr!=null && imgArr.length>0)
                esGoods.setImageUrl(imgArr[0]);
        }

        template.save(esGoods);
        return new ResultVO(true,"同步成功");
    }


    // 设置高亮字段
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段
        return highlightBuilder;
    }
}
